using System;
using System.Collections.Generic;
using System.Linq;
using Moq;
using NUnit.Framework;
using Tycho.Parser.Peg;

namespace Tycho.Parser.Tests.Peg {
    [TestFixture]
    public class LazyGrammarSpecification {
        [Test]
        public void ChangesToProductionsInPushedLanguageShouldNotAffectProductionsInOriginal () {
            var grammar = new LazyGrammar ();
            var p1 = new Mock<IProduction> ().Object;
            grammar.Productions.Add ("p1", new List<IProduction> {p1});
            var p2 = new Mock<IProduction> ().Object;
            grammar.Productions.Add ("p2", new List<IProduction> {p2});

            var newGrammar = grammar.Push ();

            var p3 = new Mock<IProduction> ().Object;
            newGrammar.Productions.Add ("p3", new List<IProduction> {p3});

            Assert.AreEqual (new [] {"p1", "p2", "p3"}, newGrammar.Productions.Keys.ToArray ());

            var oldGrammar = newGrammar.Pop ();
            Assert.AreEqual (new [] {"p1", "p2"}, oldGrammar.Productions.Keys.ToArray ());
        }

        [Test]
        public void ChangesToProductionInPushedLanguageShouldNotAffectProductionInOriginal () {
            var grammar = new LazyGrammar ();
            var p1 = new Mock<IProduction> ().Object;
            var p2 = new Mock<IProduction> ().Object;
            var productions = new List<IProduction> {p1, p2};
            grammar.Productions.Add ("p1", productions);

            var newGrammar = grammar.Push ();

            var p3 = new Mock<IProduction> ().Object;
            newGrammar.Productions["p1"].Insert (1, p3);

            Assert.AreEqual (new [] {p1, p3, p2}, newGrammar.Productions["p1"].ToArray ());

            var oldGrammar = newGrammar.Pop ();

            Assert.AreEqual (new [] {p1, p2}, oldGrammar.Productions["p1"].ToArray ());
        }

        [Test]
        public void ShouldThrowExceptionWhenNothingToPop () {
            var grammar = new LazyGrammar ();
            Assert.Throws<InvalidOperationException> (() => grammar.Pop ());
        }
    }
}